﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Admin.NET.Application.Entity;
using Admin.NET.Core.Service;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using NewLife.Caching;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Admin.NET.Application;

/// <summary>
/// 用户管理服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class UserManagementService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<UserManagement> _userManagementRep;
    private readonly ISqlSugarClient _sqlSugarClient;

    public UserManagementService(SqlSugarRepository<UserManagement> userManagementRep, ISqlSugarClient sqlSugarClient)
    {
        _userManagementRep = userManagementRep;
        _sqlSugarClient = sqlSugarClient;
    }

    /// <summary>
    /// 分页查询用户管理 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询用户管理")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<UserManagementOutput>> Page(PageUserManagementInput input)
    {
        FullRedis redisconnection = new FullRedis("121.41.14.75:6379","",0);
        var cachekey=$"UserManagement:Page{input.Page}_{input.PageSize}_{input.Keyword}";
        var cacheValue = redisconnection.Get<SqlSugarPagedList<UserManagementOutput>>(cachekey);
        if (cacheValue!=null)
        {
            return cacheValue;
        }
        else
        {
            input.Keyword = input.Keyword?.Trim();
            var query = _userManagementRep.AsQueryable()
                .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.UserAccounts.Contains(input.Keyword) || u.UserName.Contains(input.Keyword) || u.UserPhone.Contains(input.Keyword) || u.Remark.Contains(input.Keyword))
                .WhereIF(!string.IsNullOrWhiteSpace(input.UserAccounts), u => u.UserAccounts.Contains(input.UserAccounts.Trim()))
                .WhereIF(!string.IsNullOrWhiteSpace(input.UserName), u => u.UserName.Contains(input.UserName.Trim()))
                .WhereIF(!string.IsNullOrWhiteSpace(input.UserPhone), u => u.UserPhone.Contains(input.UserPhone.Trim()))
                .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim()))
                .WhereIF(input.PostId != null, u => u.PostId == input.PostId)
                .WhereIF(input.DepartmentId != null, u => u.DepartmentId == input.DepartmentId)
                .WhereIF(input.RoleId != null, u => u.RoleId == input.RoleId)
                .WhereIF(input.Sort != null, u => u.Sort == input.Sort)
                .LeftJoin<PostManagement>((u, post) => u.PostId == post.Id)
                .LeftJoin<Organization>((u, post, department) => u.DepartmentId == department.Id)
                .LeftJoin<Rolemanagement>((u, post, department, role) => u.RoleId == role.Id)
                .Select((u, post, department, role) => new UserManagementOutput
                {
                    Id = u.Id,
                    UserAccounts = u.UserAccounts,
                    UserName = u.UserName,
                    UserSex = u.UserSex,
                    UserPhone = u.UserPhone,
                    PostId = u.PostId,
                    PostFkDisplayName = $"{post.PostName}",
                    DepartmentId = u.DepartmentId,
                    DepartmentFkDisplayName = $"{department.OrganizationName}",
                    RoleId = u.RoleId,
                    RoleFkDisplayName = $"{role.RoleName}",
                    State = u.State,
                    Sort = u.Sort,
                    Remark = u.Remark,
                    IsDelete = u.IsDelete,
                    CreateTime = u.CreateTime,
                    UpdateTime = u.UpdateTime,
                    CreateUserId = u.CreateUserId,
                    CreateUserName = u.CreateUserName,
                    UpdateUserId = u.UpdateUserId,
                    UpdateUserName = u.UpdateUserName,
                });
            var result= await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
            redisconnection.Set(cachekey, result,TimeSpan.FromMinutes(3));
            return result;
        }

       
    }

    /// <summary>
    /// 获取用户管理详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取用户管理详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<UserManagement> Detail([FromQuery] QueryByIdUserManagementInput input)
    {
        return await _userManagementRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 增加用户管理 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加用户管理")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddUserManagementInput input)
    {
        var entity = input.Adapt<UserManagement>();
        return await _userManagementRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新用户管理 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新用户管理")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateUserManagementInput input)
    {
        var entity = input.Adapt<UserManagement>();
        await _userManagementRep.AsUpdateable(entity)
        .ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除用户管理 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除用户管理")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteUserManagementInput input)
    {
        var entity = await _userManagementRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _userManagementRep.FakeDeleteAsync(entity);   //假删除
        //await _userManagementRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 批量删除用户管理 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除用户管理")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteUserManagementInput> input)
    {
        var exp = Expressionable.Create<UserManagement>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _userManagementRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _userManagementRep.FakeDeleteAsync(list);   //假删除
        //return await _userManagementRep.DeleteAsync(list);   //真删除
    }
    
    /// <summary>
    /// 获取下拉列表数据 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取下拉列表数据")]
    [ApiDescriptionSettings(Name = "DropdownData"), HttpPost]
    public async Task<Dictionary<string, dynamic>> DropdownData(DropdownDataUserManagementInput input)
    {
        var postIdData = await _userManagementRep.Context.Queryable<PostManagement>()
            .InnerJoinIF<UserManagement>(input.FromPage, (u, r) => u.Id == r.PostId)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.PostName}"
            }).ToListAsync();
        var departmentIdData = await _userManagementRep.Context.Queryable<Organization>()
            .InnerJoinIF<UserManagement>(input.FromPage, (u, r) => u.Id == r.DepartmentId)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.OrganizationName}"
            }).ToListAsync();
        var roleIdData = await _userManagementRep.Context.Queryable<Rolemanagement>()
            .InnerJoinIF<UserManagement>(input.FromPage, (u, r) => u.Id == r.RoleId)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.RoleName}"
            }).ToListAsync();
        return new Dictionary<string, dynamic>
        {
            { "postId", postIdData },
            { "departmentId", departmentIdData },
            { "roleId", roleIdData },
        };
    }
    
    /// <summary>
    /// 导出用户管理记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出用户管理记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageUserManagementInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportUserManagementOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        return ExcelHelper.ExportTemplate(list, "用户管理导出记录");
    }
    
    /// <summary>
    /// 下载用户管理数据导入模板 ⬇️
    /// </summary>
    /// <returns></returns>
    [DisplayName("下载用户管理数据导入模板")]
    [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify]
    public IActionResult DownloadTemplate()
    {
        return ExcelHelper.ExportTemplate(new List<ExportUserManagementOutput>(), "用户管理导入模板", (_, info) =>
        {
            if (nameof(ExportUserManagementOutput.PostFkDisplayName) == info.Name) return _userManagementRep.Context.Queryable<PostManagement>().Select(u => $"{u.PostName}").Distinct().ToList();
            if (nameof(ExportUserManagementOutput.DepartmentFkDisplayName) == info.Name) return _userManagementRep.Context.Queryable<Organization>().Select(u => $"{u.OrganizationName}").Distinct().ToList();
            if (nameof(ExportUserManagementOutput.RoleFkDisplayName) == info.Name) return _userManagementRep.Context.Queryable<Rolemanagement>().Select(u => $"{u.RoleName}").Distinct().ToList();
            return null;
        });
    }
    
    /// <summary>
    /// 导入用户管理记录 💾
    /// </summary>
    /// <returns></returns>
    [DisplayName("导入用户管理记录")]
    [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
    public IActionResult ImportData([Required] IFormFile file)
    {
        lock (this)
        {
            var stream = ExcelHelper.ImportData<ImportUserManagementInput, UserManagement>(file, (list, markerErrorAction) =>
            {
                _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems =>
                {
                    // 链接 岗位名称
                    var postIdLabelList = pageItems.Where(x => x.PostFkDisplayName != null).Select(x => x.PostFkDisplayName).Distinct().ToList();
                    if (postIdLabelList.Any()) {
                        var postIdLinkMap = _userManagementRep.Context.Queryable<PostManagement>().Where(u => postIdLabelList.Contains($"{u.PostName}")).ToList().ToDictionary(u => $"{u.PostName}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.PostId = postIdLinkMap.GetValueOrDefault(e.PostFkDisplayName ?? "");
                            if (e.PostId == null) e.Error = "岗位名称链接失败";
                        });
                    }
                    // 链接 所在部门
                    var departmentIdLabelList = pageItems.Where(x => x.DepartmentFkDisplayName != null).Select(x => x.DepartmentFkDisplayName).Distinct().ToList();
                    if (departmentIdLabelList.Any()) {
                        var departmentIdLinkMap = _userManagementRep.Context.Queryable<Organization>().Where(u => departmentIdLabelList.Contains($"{u.OrganizationName}")).ToList().ToDictionary(u => $"{u.OrganizationName}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.DepartmentId = departmentIdLinkMap.GetValueOrDefault(e.DepartmentFkDisplayName ?? "");
                            if (e.DepartmentId == null) e.Error = "所在部门链接失败";
                        });
                    }
                    // 链接 角色
                    var roleIdLabelList = pageItems.Where(x => x.RoleFkDisplayName != null).Select(x => x.RoleFkDisplayName).Distinct().ToList();
                    if (roleIdLabelList.Any()) {
                        var roleIdLinkMap = _userManagementRep.Context.Queryable<Rolemanagement>().Where(u => roleIdLabelList.Contains($"{u.RoleName}")).ToList().ToDictionary(u => $"{u.RoleName}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.RoleId = roleIdLinkMap.GetValueOrDefault(e.RoleFkDisplayName ?? "");
                            if (e.RoleId == null) e.Error = "角色链接失败";
                        });
                    }
                    
                    // 校验并过滤必填基本类型为null的字段
                    var rows = pageItems.Where(x => {
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.UserSex == null){
                            x.Error = "性别不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.PostId == null){
                            x.Error = "岗位名称不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.DepartmentId == null){
                            x.Error = "所在部门不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.RoleId == null){
                            x.Error = "角色不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.State == null){
                            x.Error = "状态不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.Sort == null){
                            x.Error = "排序不能为空";
                            return false;
                        }
                        return true;
                    }).Adapt<List<UserManagement>>();
                    
                    var storageable = _userManagementRep.Context.Storageable(rows)
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.UserAccounts), "用户账号不能为空")
                        .SplitError(it => it.Item.UserAccounts?.Length > 50, "用户账号长度不能超过50个字符")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.UserName), "用户姓名不能为空")
                        .SplitError(it => it.Item.UserName?.Length > 50, "用户姓名长度不能超过50个字符")
                        .SplitError(it => it.Item.UserSex == null, "性别不能为空")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.UserPhone), "手机号不能为空")
                        .SplitError(it => it.Item.UserPhone?.Length > 50, "手机号长度不能超过50个字符")
                        .SplitError(it => it.Item.PostId == null, "岗位名称不能为空")
                        .SplitError(it => it.Item.DepartmentId == null, "所在部门不能为空")
                        .SplitError(it => it.Item.RoleId == null, "角色不能为空")
                        .SplitError(it => it.Item.State == null, "状态不能为空")
                        .SplitError(it => it.Item.Sort == null, "排序不能为空")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.Remark), "备注不能为空")
                        .SplitError(it => it.Item.Remark?.Length > 300, "备注长度不能超过300个字符")
                        .SplitInsert(_ => true)
                        .ToStorage();
                    
                    storageable.BulkCopy();
                    storageable.BulkUpdate();
                    
                    // 标记错误信息
                    markerErrorAction.Invoke(storageable, pageItems, rows);
                });
            });
            
            return stream;
        }
    }
}
